import os, sys, time
import threading, traceback

parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 5)))
sys.path.insert(0, parent_path)

from core.task.modules.task_lines.base_task import BaseTask
from core.utils.logger import logging

class LoopTask(BaseTask):
    """任务流程, 必定包含predictor """
    def __init__(self,
                 predictor, 
                 process,
                 preprocess, 
                 postprocess, 
                 detector_tags = [],
                 keep_keys=[],
                 done_key=None,
                 LoopTask_fps = 1,
                 ) -> None:
        super().__init__(predictor,process,preprocess,postprocess,detector_tags)
        self.fps = LoopTask_fps
        self.run_loop_thread = None
        self.keeps = {}
        self.kepp_keys = keep_keys
        self.done_key = done_key
        self.wait_time = 1/self.fps
        self.dymamic_frame_idx = 0

    def set(self,data):
        super().set(data)
        if data.get("LoopTask_fps",False):
            self.fps = data["LoopTask_fps"]
        for key in self.kepp_keys:
            if data.get(key,False):
                self.keeps[key] = data[key]
     
    def run_loop(self):
        try:
            data = {}
            while self.is_running():
                data.clear()
                data["detector_tags"] = self.detector_tags
                data.update(self.keeps)
                for processor in self.exe_seq:
                    data = processor(data)
                if self.done_key is not None:
                    if data.get(self.done_key,False):
                        logging.info("|data[done_key] is True|")
                        self.close()
                self.dymamic_frame_idx+=1
                time.sleep(self.wait_time)
        except:
            logging.error(traceback.format_exc())
            self.close()
        finally:
            logging.info("|task run_loop done.|")


    def dymamic_fps_loop(self):
        try:
            while True:
                time.sleep(1)
                if self.is_running():
                    break
                elif self.is_close():
                    break

            start_time = time.time()
            self.dymamic_frame_idx = 0
            while self.is_running():
                if self.dymamic_frame_idx>=self.fps*10:
                    fps = self.dymamic_frame_idx/(time.time()-start_time)
                    if fps/self.fps<0.95:
                        scale = max(fps/self.fps,0.8)
                    elif fps/self.fps>1.01:
                        scale = min(fps/self.fps,1.2)
                    else:
                        scale = 1
                    self.wait_time=max(self.wait_time*scale,1/1000)
                    # print("now fps: {}, wait_time:{}, scale: {}\n".format(fps,self.wait_time, scale))
                    self.dymamic_frame_idx = 0
                    start_time = time.time()
                time.sleep(5)
        except Exception:
            logging.error(traceback.format_exc())
            self.close()

        
    def __call__(self, data):
        self.standby()
        self.status = 2
        self.run_loop_thread.start()
        self.dymamic_fps_loop_thread.start()
        return data

    def standby(self):
        try:
            super().standby()
            self.run_loop_thread = threading.Thread(target=self.run_loop)
            self.dymamic_fps_loop_thread = threading.Thread(target=self.dymamic_fps_loop)
        except Exception as e:
            raise e
